#ifndef OCTREE_H
#define OCTREE_H

#include "glm/glm.hpp"
#include "primitive.h"
#include "scene.h"

#include <QSharedPointer>
#include <QVector>
#include <QList>

//This class represents a node in the Octree

class OctreeNode {

    // OctreeNode Constructor
    // origin       - central point of the bounding box
    // dimension    - size in terms of space
    // depth        - the maximum number of subdivisions that can occur
public:
    OctreeNode( const glm::vec4 &origin, float dimension, unsigned int depth );
    // Just calls the scene's primitives collision methods against this node and updates this nodes state
//    void verifyCollision();
//    void subdivide();                       // Not a leaf node? subdivide
//    bool isLeaf() const;
//    const Box & getBoundary() const;
//    CollisionState getCollisionState() const;

    //TODO: Attributes are public. Leave like this or implement getters and setters?
    glm::mat4x4 transform;
    bool  m_is_leaf;                                // This node is a leaf?
    int m_depth;                                    // This node's depth
    QVector<QSharedPointer<OctreeNode> > m_children;            // If the node isnt a leaf, it has 8 children
    Box m_node_boundbox;                           // This node's boundbox
    CollisionState m_state;                         // The state of this node
    QSharedPointer<Frame> m_frame;
};


class Octree{
public:
    Octree( const glm::vec4 &origin = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f), float dimension = 1.0f, int max_depth = 5 );
    ~Octree();
    void subdivide(Scene *scene, int max_depth = 5);
    void insert_node(OctreeNode*);
    QList<OctreeNode*> m_nodes;
    void set_visible(bool);
    bool is_visible();
    void set_wireframe(bool);
    void set_solid(bool);
    bool wireframe();
    bool solid();
    void set_nodes_visibility(CollisionState state, bool visibility);
    bool get_nodes_visibility(CollisionState state);
    QSharedPointer<Frame> m_root_frame;

    float x_rot;
    float y_rot;
    float z_rot;
    float x_tr;
    float y_tr;
    float z_tr;
    float x_sc;
    float y_sc;
    float z_sc;
private:
    void subdivide_node(OctreeNode*);
    void verify_collision(OctreeNode*);
    OctreeNode *m_root;
    OctreeNode *m_curr_node;

    int m_tree_depth;
    int m_max_depth;
    Scene *m_current_scene;
    bool m_visible;
    bool m_wireframe;
    bool m_solid;
    bool m_show_in_nodes;
    bool m_show_out_nodes;
    bool m_show_partial_nodes;
};


#endif // OCTREE_H
